/**
 * Object for graphical representation of data.
 * @constructor
 */
View = function() {};

/**
 * Display transition from login screen to main screen. 
 * @public
 */
View.transitionLogin = function() {
  $("#login").slideUp(View.transition_duration, function() {
    $("#subjects").slideDown(View.transition_duration_);
    $("#wrapper_user_info").fadeIn(View.transition_duration_);
  });
};

/**
 * Display transition from main screen to login screen.
 * @public
 */
View.transitionLogout = function() {
  $("#subjects").slideUp(View.transition_duration, function() {
    $("#login").slideDown(View.transition_duration_);
    $("#wrapper_user_info").fadeOut(View.transition_duration_);
  });
};

/**
 * Display login spinner signaling that server is being asked.
 * @public
 */
View.spinnerShow = function(buttonId) {
  $('#' + buttonId + '_spinner').remove();
  $('#' + buttonId).after(sprintf('<div class="spinner" id="%1_spinner"></div>',
                                  buttonId));
  $('#' + buttonId + '_spinner').hide().fadeIn(View.transition_duration_);
};

/**
 * Hide login spinner signaling that server is being asked.
 * @public
 */
View.spinnerHide = function(buttonId) {
  $('#' + buttonId + '_spinner').fadeOut(View.transition_duration_, function() {
    $(this).remove();
  });
};

/**
 * Show error on login screen.
 * @public
 */
View.errorShow = function(buttonId, error) {
  $(sprintf("#%1_error, #%1_spinner", buttonId)).remove();
  $('#' + buttonId).
      after(sprintf('<div class="error" id="%1_error">%2</div>',
                    buttonId,
                    View.errors_[error] || View.errors_.unknown));
  $('#' + buttonId + '_error').hide().fadeIn(View.transition_duration_);
  setTimeout(function() {
    View.errorHide(buttonId);
  }, 5000);
};

/**
 * Hide error on login screen.
 * @public
 */
View.errorHide = function(buttonId) { 
  $('#' + buttonId + '_error').fadeOut(View.transition_duration_, function() {
    $(this).remove();
  });
};

/**
 * Display that subjects are being sorted.
 * @public
 * 
 * @param {string} by what the subjects are ordered
 * @param {boolean} ascending
 */
View.displayOrder = function(by, ascending) {
  if (typeof by !== "string" || typeof ascending !== "boolean") {
    return error("Invalid argument");
  }
  $(".table_header div").removeClass("sorted_asc sorted_desc");
  $("#subjects_" + by + ", #subjects_1_" + by).
      addClass(ascending ? "sorted_asc" : "sorted_desc");
}

/**
 * Clear and fill table.
 * @public
 * 
 * @param {array} subjects
 */
View.refreshAllSubjects = function(isTeacher, subjects, callback) {
  if (typeof isTeacher !== "boolean" || typeof subjects !== "object") {
    return error("Illegal argument");
  }
  var filled = false;
  var fillContent = function(callbackInner) {
    if (filled) return;
    filled = true;
    var innerHtml = isTeacher ? View.table_header_subjects_teacher_ :
                                View.table_header_subjects_student_;
    for (var i in subjects) {
      var s = subjects[i];
      innerHtml +=
          sprintf("<div class='row subject_row %1 %2' id='subject_row_%3'>",
                  "read",
                  "nonempty",
                  s.id) +
          sprintf("<div class='cell'>%1</div>", s.name) +
          sprintf(isTeacher ? "" : "<div class='cell'>%1</div>", s.todo) +
          sprintf(isTeacher ? "" : "<div class='cell'>%1</div>", s.done) +
          sprintf(isTeacher ? "" : "<div class='cell'>%1</div>", s.countOfMessages) +
          "</div>";
    }
    $("#table_subjects").html(innerHtml + (isTeacher ? View.table_footer_subjects_teacher : 
                                                       View.table_footer_subjects_student));
    if(typeof callbackInner === "function") callbackInner.call();
  }
  
  var $subjects = $(".subject");
  if ($subjects.length === 0) {
    fillContent(callback);
  } else {
    $subjects.slideUp(View.transition_duration_, function() {
      $(this).remove();
      fillContent(callback);
    });
  }
};

/** @public */
View.refreshSubject = function(isTeacher, subject, subjectId, callback) {
  if(typeof isTeacher !== "boolean" || typeof subject !== "object" ||
     (typeof subjectId !== "string" && typeof subjectId !== "number")) {
    return error(arguments);
  }
  $(".test").slideUp(View.transition_duration_, function() {
	$(this).remove();
	var innerHtml = isTeacher ? View.table_header_subject_teacher_ :
                                View.table_header_subject_student_;
    var doneTests = 0;
    var allTests = 0;
    var messagesCount = 0;
    for(var tId in subject.tests){
      var t = subject.tests[tId];
      for(var rId in t.running){
		  if(t.running[rId].done){
			  doneTests++;
		  }
		  allTests++;
		  for(var mId in t.running[rId].messages){
			  messagesCount++;
		  }
	  }
	  innerHtml += sprintf("<div class='row test_row' id='test_row_%1'>",
                         test.id) +
                   sprintf("<div class='cell'>%1</div>", test.name) +
                   sprintf("<div class='cell'>%1/%2</div>", testsDone,
                           allTests) +
                   sprintf("<div class='cell'>%1</div>", test.deadline) +
                   sprintf(isTeacher ? "" : "<div class='cell'>%1</div>",
                           messagesCount) +
                 "</div>";
    }
    $("#subject_row_" + subjectId).html(innerHtml + (isTeacher ? View.table_footer_subject_teacher : 
                                                                 View.table_footer_subject_student));
    if (typeof callback === "function") callback.call();
  });
}

/** @public */
View.refreshTest = function(isTeacher, test, testId, callback) {
  if (typeof isTeacher !== "boolean" || typeof subjects !== "object") {
    return error("Illegal argument");
  }
  error("View.refreshTest: Not implemented yet.");
  if (typeof callback === "function") callback.call();
}

View.refreshRunning = function(isTeacher, running, runId, callback) {
  if (typeof isTeacher !== "boolean" || typeof running !== "object") {
    return error("Illegal argument");
  }
  error("View.refreshRunning: Not implemented yet.");
  if (typeof callback === "function") callback.call();
}

/**
 * Show extended information about subject. Note that id is required.
 * @public
 * 
 * @param {object} subject
 */
View.subjectShow = function(isTeacher, subject, callback) {
  if (typeof isTeacher !== "boolean" || typeof subject !== "object" ||
      (typeof subject.id !== "string" && typeof subject.id !== "number")) {
    return error(arguments);
  }
  var innerHtml = sprintf(isTeacher ? View.table_header_subject_teacher_ :
                                      View.table_header_subject_student_,
                          subject.id);
  for (var testId in subject.tests) {
    var test = subject.tests[testId];
	if(!isTeacher && !test.active) continue;
    innerHtml += sprintf("<div class='row test_row' id='test_row_%1'>",
                         test.id) +
                   sprintf("<div class='cell'>%1</div>", test.name) +
                   sprintf("<div class='cell'>%1/%2</div>", test.testsDone,
                           test.allTests) +
                   sprintf("<div class='cell'>%1</div>", test.deadline) +
                   (isTeacher ?
                    sprintf("<div class='cell'>%1</div>",
                            test.active ? 'yes' : 'no') : 
                    sprintf("<div class='cell'>%1</div>", test.messagesCount)) +
                 "</div>";
  }
  $("#subject_row_" + subject.id).
      after(innerHtml + View.table_footer_subject_);
  $("#subject_" + subject.id).
    hide().
    slideDown(View.transition_duration_, function() {
      if (typeof callback === "function") callback.call();
    });
}

/**
 * Hide extended information about subject.
 * @public
 * 
 * @param {string|number} subjectId
 */
View.subjectHide = function(subjectId, callback) {
  if (typeof subjectId !== "string") {
    return error(arguments);
  }
  $("#subject_" + subjectId).
      slideUp(View.transition_duration_, function() {
        $(this).remove();
        if (typeof callback === "function") callback.call();
      });
}

/**
 * Show extended information about test. Note that id is required.
 * @public
 * 
 * @param {object} test
 */
View.testShow = function(isTeacher, test, callback) {
  if (typeof isTeacher !== "boolean" || typeof test !== "object" ||
      (typeof test.id !== "string" && typeof test.id !== "number")) {
    return error(arguments);
  }
  var innerHtml = sprintf(isTeacher ? View.table_header_test_teacher_ :
                                      View.table_header_test_student_,
                          test.id, (test.active ? "disabled" : ""));
  
  if(isTeacher && !test.active){
	for(var reqId in test.required_files){
		var req_file = test.required_files[reqId];
		innerHtml +=
        sprintf("<div class='row req_row' id='req_row_%1'>", reqId) +
          sprintf("<div class='cell'>%1</div>", req_file.filename) +
          sprintf("<div class='cell'>%1</div>", "upload") +
          sprintf("<div class='cell'>%1</div>", req_file.submitted) +
        "</div>";
	}
  }
  for(var runningId in test.running){
    var running = test.running[runningId];
    innerHtml +=
        sprintf("<div class='row running_row' id='running_row_%1'>", running.id) +
          sprintf(isTeacher ? "<div class='cell'>%1</div>" : "", running.student) +
          sprintf("<div class='cell'>%1</div>", running.done = running.done ? 'yes' : 'no') +
          sprintf("<div class='cell'>%1</div>", running.submitted) +
          sprintf(isTeacher ? "" : "<div class='cell'>%1</div>", running.messages) +
        "</div>";
  }
  $("#test_row_" + test.id).after(innerHtml + View.table_footer_test_);
  $("#test_" + test.id).
      hide().
      slideDown(View.transition_duration_, function() {
        if (typeof callback === "function") callback.call();
      });
}

/**
 * Hide extended information about test.
 * @public
 * 
 * @param {string|number} testId
 */
View.testHide = function(testId, callback) {
  if(typeof testId !== "string" && typeof testId !== "number") {
    return error(arguments);
  }
  $("#test_" + testId).slideUp(View.transition_duration_, function() {
    $(this).remove();
    if (typeof callback === "function") callback.call();
  });
}

/**
 * Show extended information about test. Note that id is required.
 * @public
 * 
 * @param {object} test
 */
View.runningShow = function(isTeacher, running, callback) {
  if (typeof isTeacher !== "boolean" || typeof running !== "object" ||
      (typeof running.id !== "string" && typeof running.id !== "number")) {
    return error(arguments);
  }
  var innerHtml = sprintf(isTeacher ? View.table_header_running_teacher_ :
                                      View.table_header_running_student_,
                          running.id);
  for(var messageId in running.messages){
    var message = running.messages[messageId];
    innerHtml +=
        sprintf("<div class='row message_row' id='message_row_%1'>",
                message.id) +
          sprintf("<div class='cell'><b>From: </b>%1</div>", message.from) +
          sprintf("<div class='cell'><b>Time: </b>%1</div><br>", message.time) +
          sprintf("<div class='cell'>%1</div>", message.content) +
        "</div>";
  }
  $("#running_row_" + running.id).after(innerHtml + View.table_footer_running_);
  $("#running_" + running.id).
      hide().
      slideDown(View.transition_duration_, function() {
        if (typeof callback === "function") callback.call();
      });
}

/**
 * Hide extended information about test.
 * @public
 * 
 * @param {string|number} testId
 */
View.runningHide = function(runningId, callback) {
  if(typeof runningId !== "string" && typeof runningId !== "number") {
    return error(arguments);
  }
  $("#running_" + runningId).slideUp(View.transition_duration_, function() {
    $(this).remove();
    if (typeof callback === "function") callback.call();
  });
}

/**
 * Show extended information about message. Note that id is required.
 * @public
 * 
 * @param {object} message
 */
View.messageShow = function(isTeacher, message, callback) {
  if (typeof isTeacher !== "boolean" || typeof message !== "object" ||
      (typeof message.id !== "string" && typeof message.id !== "number")) {
    return error(arguments);
  }
  $("#message_row_" + message.id).
      after(sprintf(isTeacher ? View.table_header_message_teacher_ :
                                View.table_header_message_student_,
                    message.id) +
            sprintf("<div class='row message_item' id='message_%1'>",
                    message.id) +
              sprintf("<div class='cell'>%1</div>", (isTeacher ? message.to : message.from)) +
              sprintf("<div class='cell'>%1</div>", message.content) +
              sprintf("<div class='cell'>%1</div>", message.sent) +
            "</div>" +
            View.table_footer_message_);
  $("#message_" + message.id).
      hide().
      slideDown(View.transition_duration_, function() {
        if (typeof callback === "function") callback.call();
      });
}

/**
 * Hide extended information about message.
 * @public
 * 
 * @param {string|number} messageId
 */
View.messageHide = function(messageId, callback) {
  if (typeof messageId !== "string" && typeof messageId !== "number") {
    return error(arguments);
  }
  $("#message_" + messageId).
      slideUp(View.transition_duration_, function() {
    $(this).remove();
    if (typeof callback === "function") callback.call();
  })
}

/** @public */
View.messageRead = function(messageId) {
  if (typeof messageId !== "string" && typeof messageId !== "number") {
    return error(arguments);
  }
  error("View.messageRead: Not implemented yet.");
}

/** @public */
View.addStudentToMessage = function(name, messageId){
  if (typeof name !== "string" || typeof messageId !== "string") {
    return error(arguments);
  }
  error("View.addStudentToMessage: Not implemented yet.");
}

/** @private */
View.transition_duration = 400;
  
/** @private */
View.errors_ = {
  "empty_password": "Empty password.",
  "short_password": "Short password.",
  "empty_login": "Empty login.",
  "short_login": "Short login.",
  "incorrect_login": "Incorrect login or password.",
  "database_error": "Error ocured in database.",
  "wrong_parameter": "Wrong parameter.",
  "already_done": "Test is already done",
  "upload_failed": "Upload failed.",
  "after_deadline": "You are late.",
  "not_active": "Test is not open for submitting.",
  "wrong_time": "Wrong type of date (DD/MM/YYYY)",
  "unknown": "Unknown error."
};

/** @private */
View.table_header_subjects_student_ =
    "<div class='row table_header'>" +
      "<div class='cell' id='subjects_name'>Subject</div>" +
      "<div class='cell' id='subjects_todo'>Tests To Do</div>" +
      "<div class='cell' id='subjects_done'>Tests Done</div>" +
      "<div class='cell' id='subjects_unread'>Messages</div>" +
    "</div>";

/** @private */
View.table_header_subjects_teacher_ =
    "<div class='row table_header'>" +
      "<div class='cell' id='subjects_name'>Subject</div>" +
    "</div>";

/** @private */
View.table_footer_subjects_student =
    "<div class='row table_header'>" +
      "<div class='cell' id='subjects_name'>Subject</div>" +
      "<div class='cell' id='subjects_todo'>Tests To Do</div>" +
      "<div class='cell' id='subjects_done'>Tests Done</div>" +
      "<div class='cell' id='subjects_unread'>Messages</div>" +
    "</div>";

/** @private */
View.table_footer_subjects_teacher =
    "<div class='row table_header'>" +
      "<div class='cell' id='subjects_name'>Subject</div>" +
    "</div>";

/** @private */
View.table_header_subject_student_ =
    "<div class='row subject' id='subject_%1'>" +
      "<div class='row subject_header'>" +
        "<div class='cell'>Test</div>" +
        "<div class='cell'>Done/All Tests</div>" +
        "<div class='cell'>Deadline</div>" +
        "<div class='cell'>Messages</div>" +
      "</div>";

/** @private */
View.table_header_subject_teacher_ =
    "<div class='row subject' id='subject_%1'>" +
      "<div class='row subject_options'>" +
        "<form action='/' method='post' id='subject_options_form_%1' enctype='multipart/form-data'>" +
          "<input type='text' id='subject_options_name_%1' placeholder='Test Name'>" +
          "<input type='text' id='subject_options_deadline_%1' placeholder='Deadline'>" +
          "<input type='text' id='subject_options_solution_filename_%1' placeholder='Solution Filename'>" +
          "<input type='text' class='long' id='subject_options_compilation_command_%1' placeholder='Compiling Command'>" +
          "<input type='text' class='long' id='subject_options_running_command_%1' placeholder='Running Command'>" +
          "<input type='button' id='subject_options_add_test_%1' value='Add Test'>" +
        "</form>" +
      "</div>" +
      "<div class='row subject_header'>" +
        "<div class='cell'>Test</div>" +
        "<div class='cell'>Done/All Tests</div>" +
        "<div class='cell'>Deadline</div>" +
        "<div class='cell'>Active</div>" +
      "</div>";

/** @private */
View.table_footer_subject_ =
    "</div>";


/** @private */
View.table_header_test_student_ =
    "<div class='row test' id='test_%1'>" +
      "<div class='row test_options'>" +
        "<form action='/run_test' method='post' id='test_options_form_%1' enctype='multipart/form-data'>" +
          "<input type='file' name='fileeee_%1' size='10000000' id='test_options_running_file_%1'>" +
          "<input type='hidden' name='testId' id='test_options_test_id_%1'>" +
          "<input type='button' id='test_options_submit_solution_%1' value='Submit Solution'> " +
        "</form>" +
      "</div>" +
      "<div class='row test_header'>" +
        "<div class='cell'>Done</div>" +
        "<div class='cell'>Submitted</div>" +
        "<div class='cell'>Messages</div>" +
      "</div>";

/** @private */
View.table_header_test_teacher_ =
    "<div class='row test' id='test_%1'>" +
      "<div class='row test_options'>" +
        "<form action='/add_file' method='post' id='test_options_form_%1' enctype='multipart/form-data'>" +
          "<input type='file' name='file' size='10000000' id='test_options_file_%1'>" +
          "<input type='text' name='filename' id='test_options_filename_%1' placeholder='Filename'>" +
          "<input type='hidden' name='testId' id='test_options_test_id_%1'>" +
          "<br>" +
          "<input type='button' id='test_options_add_test_file_%1' value='Add Test File' %2>" +
          "<input type='button' id='test_options_activate_test_%1' value='Activate Test' %2>" +
        "</form>" +
      "</div>" +
      "<div class='row test_header'>" +
        "<div class='cell'>Student</div>" +
        "<div class='cell'>Result</div>" +
        "<div class='cell'>Submitted</div>" +
      "</div>";

/** @private */
View.table_footer_test_ =
    "</div>";

/** @private */
View.table_header_running_student_ =
    "<div class='row running' id='running_%1'>";

/** @private */
View.table_header_running_teacher_ =
    "<div class='row running' id='running_%1'>" +
      "<div class='row running_options'>" +
        "<input type='button' id='running_options_comment_button_%1' value='Comment test'>" +
        "<br>" +
        "<textarea id='running_options_comment_%1' placeholder='Content'></textarea>" +
      "</div>" +
      "<div class='row running_header'>" +
      "</div>";

/** @private */
View.table_footer_running_ =
    "</div>";
